package e.odbo.data.dao.table;

import com.openbravo.data.loader.*;
import com.openbravo.data.loader.serialize.serializer.SerializerRead;
import com.openbravo.data.loader.serialize.serializer.SerializerWrite;
import com.openbravo.data.loader.serialize.serializer.read.SerializerReadBasic;
import com.openbravo.data.loader.serialize.serializer.read.SerializerReadBasicExt;
import com.openbravo.data.loader.serialize.serializer.write.SerializerWriteBasic;
import com.openbravo.data.loader.serialize.serializer.write.SerializerWriteBasicExt;
import e.odbo.data.bean.key.IKeyGetter;
import e.odbo.data.bean.key.KeyGetterBasic;
import e.odbo.data.bean.key.KeyGetterFirst;
import com.openbravo.data.loader.serialize.Datas;
import e.odbo.data.model.Column;
import e.odbo.data.model.ColumnFlag;
import e.odbo.data.model.Table;
import e.odbo.data.format.Formats;
import e.odbo.data.model.smaple.TimeLogAble;

import java.util.*;

public  class TableDefinition {
    public static int UPDATEDATE_NoSuport = -1;

    public String tablename;
    public String[] fieldname;
    public String[] fieldtran;
    public Datas[] fielddata;
    public Formats[] fieldformat;
    public boolean[] updateIgnoreField;
    public Map<Class, String> parentRefMap = new HashMap<Class, String>();
    public int[] idinx;
    public int dateindex;

    /**
     * Creates a new instance of TableDefinition
     */
    public TableDefinition(
            String tablename,
            String[] fieldname, String[] fieldtran, Datas[] fielddata, Formats[] fieldformat,
            int[] idinx, int dateinx) {
        this.tablename = tablename;

        this.fieldname = fieldname;
        this.fieldtran = fieldtran;
        this.fielddata = fielddata;
        this.fieldformat = fieldformat;

        this.idinx = idinx;
        this.dateindex = dateinx;
        updateIgnoreField = null;
    }

    public TableDefinition(
            String tablename,
            String[] fieldname, String[] fieldtran, Datas[] fielddata, Formats[] fieldformat,
            int[] idinx) {
        this(tablename, fieldname, fieldname, fielddata, fieldformat, idinx, UPDATEDATE_NoSuport);
    }

    public TableDefinition(
            String tablename,
            String[] fieldname, Datas[] fielddata, Formats[] fieldformat,
            int[] idinx) {
        this(tablename, fieldname, fieldname, fielddata, fieldformat, idinx);
    }

    public TableDefinition(
            String tablename,
            Field[] fields,
            int[] idinx) {
        this.tablename = tablename;

        this.fieldname = new String[fields.length];
        this.fieldtran = new String[fields.length];
        this.fielddata = new Datas[fields.length];
        this.fieldformat = new Formats[fields.length];
        updateIgnoreField = new boolean[fields.length];
        dateindex = UPDATEDATE_NoSuport;
        for (int i = 0; i < fields.length; i++) {
            fieldname[i] = fields[i].getLabel();
            fieldtran[i] = fields[i].getLabeltran();
            fielddata[i] = fields[i].getData();
            fieldformat[i] = fields[i].getFormat();
            updateIgnoreField[i] = fields[i].isUpdateIgnore();
            if (fields[i].getParentClass() != null)
                parentRefMap.put(fields[i].getParentClass(), fields[i].getLabel());
            if (fields[i].getLabel().equalsIgnoreCase(TimeLogAble.LASTMODIFIED))
                dateindex = i;
        }
        this.idinx = idinx;
    }


    public TableDefinition(
            String tablename,
            Field[] fields,
            int idinx) {
        this(tablename,fields,new int[]{idinx});
    }

    public TableDefinition() {

    }

    //当没有外部引用时可用此
    public TableDefinition(Table table) {
         this.tablename=table.getName();
         Column[] columns= table.getColumns();
        this.fieldname = new String[columns.length];
        this.fieldtran = new String[columns.length];
        this.fielddata = new Datas[columns.length];
        this.fieldformat = new Formats[columns.length];
        updateIgnoreField = new boolean[columns.length];
        List<Integer> idinxs=new ArrayList<>();
        for (int i = 0; i < columns.length; i++) {
            fieldname[i] = columns[i].getName();
            fieldtran[i] = columns[i].getComment();
            fielddata[i] = columns[i].getColumnType().getDataType();
            fieldformat[i] = columns[i].getColumnType().getFormat();
            updateIgnoreField[i] = false;
            if (columns[i].getName().equalsIgnoreCase(TimeLogAble.LASTMODIFIED))
                dateindex = i;
            if(ColumnFlag.isPK(columns[i].getColumnFlag()))
                idinxs.add(i);
        }
        this.idinx = new int[idinxs.size()];
        for(int i=0;i<idinxs.size();i++)
            idinx[i]=idinxs.get(i);
    }

    public int getColumnCount() {
        return fieldname.length;
    }

    public int getUpdateColumnCount() {
        int realLength = getColumnCount();
        if (updateIgnoreField == null)
            return realLength;
        for (boolean f : updateIgnoreField)
            if (f)
                realLength--;
        return realLength;
    }

    public String getTableName() {
        return tablename;
    }

    public Formats[] getFieldformat() {
        return fieldformat;
    }

    public String[] getFields() {
        return fieldname;
    }

    public String[] getKeyFields() {
        String[] keyFields = new String[idinx.length];
        for (int i : idinx)
            keyFields[i] = fieldname[idinx[i]];
        return keyFields;
    }

    public Vectorer getVectorerBasic(int[] aiFields) {
        return new VectorerBasic(fieldtran, fieldformat, aiFields);
    }

    public IRenderString getRenderStringBasic(int[] aiFields) {
        return new RenderStringBasic(fieldformat, aiFields);
    }

    public ComparatorCreator getComparatorCreator(int[] aiOrders) {
        return new ComparatorCreatorBasic(fieldtran, fielddata, aiOrders);
    }

    public IKeyGetter getKeyGetterBasic() {
        if (idinx.length == 1) {
            return new KeyGetterFirst(idinx);
        } else {
            return new KeyGetterBasic(idinx);
        }
    }

    public int getFieldIndex(String field) {
        int ind = -1;
        for (int i = 0; i < this.getColumnCount(); i++)
            if (this.fieldname[i].equalsIgnoreCase(field)) {
                ind = i;
                break;
            }
        return ind;
    }

    public int[] getFieldsIndex(String[] field) {
        int[] ind = new int[field.length];
        for (int j = 0; j < field.length; j++)
            for (int i = 0; i < this.getColumnCount(); i++)
                if (this.fieldname[i].equalsIgnoreCase(field[j])) {
                    ind[j] = i;
                    break;
                }
        return ind;
    }

    public Datas getDatas(int index) {
        return this.fielddata[index];
    }

    public void addField(Field aField) {
        int i = fieldname.length;
        fieldname = Arrays.copyOf(fieldname, i + 1);
        fieldname[i] = aField.getLabel();

        fieldtran = Arrays.copyOf(fieldtran, i + 1);
        fieldtran[i] = aField.getLabeltran();

        fielddata = Arrays.copyOf(fielddata, i + 1);
        fielddata[i] = aField.getData();

        fieldformat = Arrays.copyOf(fieldformat, i + 1);
        fieldformat[i] = aField.getFormat();
        this.updateIgnoreField = Arrays.copyOf(updateIgnoreField, i + 1);
        updateIgnoreField[i] = aField.isUpdateIgnore();

        if (aField.getParentClass() != null)
            parentRefMap.put(aField.getParentClass(), aField.getLabel());
    }

    public Field[] getTableFields() {
        Field[] ret = new Field[fieldname.length];
        for (int i = 0; i < fieldname.length; i++) {
            ret[i] = new Field(fieldname[i], fielddata[i], fieldformat[i], fieldtran[i]);
        }
        return ret;
    }

    public SerializerRead getSerializerReadBasic() {
        return new SerializerReadBasic(fielddata);
    }

    public SerializerRead getSerializerReadBasic(int[] fieldindx) {
        return new SerializerReadBasicExt(fielddata, fieldindx);
    }

    public SerializerWrite getSerializerInsertBasic(int[] fieldindx) {
        return new SerializerWriteBasicExt(fielddata, fieldindx);
    }

    public SerializerWrite getSerializerDeleteBasic() {
        return new SerializerWriteBasicExt(fielddata, idinx);
    }

    public SerializerWrite getSerializerExistBasic() {
        return new SerializerWriteBasicExt(fielddata, idinx);
    }

    public SerializerWrite getSerializerUpdateBasic(int[] fieldindx) {

        int[] aindex = new int[fieldindx.length + idinx.length];

        System.arraycopy(fieldindx, 0, aindex, 0, fieldindx.length);

        System.arraycopy(idinx, 0, aindex, fieldindx.length, idinx.length);

        return new SerializerWriteBasicExt(fielddata, aindex);
    }

    public int[] getAllFields() {

        int[] fieldindx = new int[fieldname.length];
        for (int i = 0; i < fieldname.length; i++) {
            fieldindx[i] = i;
        }
        return fieldindx;
    }


    public String getDateFieldName() {
        if (dateindex != UPDATEDATE_NoSuport)
            return fieldname[dateindex];
        return null;
    }

    public TableDefinition getInfoTableDefinition(int[] indexs){
        String[] fieldname1=new String[indexs.length];
        String[] fieldtran1=new String[indexs.length];
        Datas[] fielddata1=new Datas[indexs.length];
        Formats[] fieldformat1=new Formats[indexs.length];
        int[] idinx1=new int[idinx.length];
        for(int i=0;i<indexs.length;i++){
            fieldname1[i]=fieldname[indexs[i]];
            fieldtran1[i]=fieldtran[indexs[i]];
            fielddata1[i]=fielddata[indexs[i]];
            fieldformat1[i]=fieldformat[indexs[i]];
            for(int j=0;j<idinx.length;j++){
                if(idinx[j]==indexs[i])
                    idinx1[j]=i;
            }
        }
        return new TableDefinition(tablename, fieldname1, fieldtran1, fielddata1,fieldformat1,idinx1);
    }

    public String getParentFieldName(Class c) {
        return parentRefMap.get(c);
    }


    public Datas[] getDatas() {
        return fielddata;
    }

    public String getDefaultListOrder(String alise) {
        return "";
    }

    public int[] getIdinx() {
        return idinx;
    }

    public Datas getSerializerWriteData(String field) {
        return fielddata[Arrays.asList(fieldname).indexOf(field)];
    }

    public SerializerWrite getSerializerWriteBase(String[] fields) {
        if (fields.length == 1)
            return new SerializerWriteBasic(getSerializerWriteData(fields[0]));
        Datas[] datas1 = new Datas[fields.length];
        for (int i = 0; i < fields.length; i++)
            datas1[i] = getSerializerWriteData(fields[i]);
        return new SerializerWriteBasic(datas1);
    }
}
